/******************************************************************************
 * Product: Adempiere ERP & CRM Smart Business Solution                        *
 * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved.                *
 * This program is free software; you can redistribute it and/or modify it    *
 * under the terms version 2 of the GNU General Public License as published   *
 * by the Free Software Foundation. This program is distributed in the hope   *
 * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.           *
 * See the GNU General Public License for more details.                       *
 * You should have received a copy of the GNU General Public License along    *
 * with this program; if not, write to the Free Software Foundation, Inc.,    *
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.                     *
 * For the text or an alternative of this public license, you may reach us    *
 * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA        *
 * or via info@compiere.org or http://www.compiere.org/license.html           *
 *****************************************************************************/
package org.adempiere.apps.form;

import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.VetoableChangeListener;
import java.sql.*;
import java.util.*;
import java.util.logging.*;
import java.math.*;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

import org.adempiere.model.MLoading;
import org.adempiere.model.MLoadingLine;
import org.compiere.apps.*;
import org.compiere.apps.form.FormFrame;
import org.compiere.apps.form.FormPanel;
import org.compiere.grid.ed.*;
import org.compiere.minigrid.*;
import org.compiere.model.*;
import org.compiere.swing.*;
import org.compiere.util.*;
/**
 *  Barcode reader form for shipment
 *
 *  @author  Shindu
 *  @version 1.0
 *  @since Nov 2011
 */


public class ShipmentBarcodeChecker extends CPanel
	implements FormPanel, ActionListener, TableModelListener, VetoableChangeListener
{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 122212L;

	/**
	 *	Initialize Panel
	 *  @param WindowNo window
	 *  @param frame frame
	 */
	public void init (int WindowNo, FormFrame frame)
	{
			
		log.info(frame.toString());
		p_WindowNo = WindowNo;
		m_frame = frame;
		
		try
		{
			initBPartner(true);
			dynInit();
			jbInit();			
			confirmPanel.addActionListener(this);
			confirmPanel.setOKVisible(false);
			//  Set status
			statusBar.setStatusDB("");
			//tableChanged(null);
			p_initOK = true;
		}
		catch(Exception e)
		{
			log.log(Level.SEVERE, "", e);
			p_initOK = false;
		}
		//AEnv.positionCenterWindow(Env.getWindow(p_WindowNo), this);
	}	//	init
	
	protected void initBPartner (boolean forInvoice) throws Exception
	{
		//  load BPartner
		int AD_Column_ID = 3499;        //  C_Invoice.C_BPartner_ID
		MLookup lookup = MLookupFactory.get (Env.getCtx(), p_WindowNo, 0, AD_Column_ID, DisplayType.Search);
		bPartnerField = new VLookup ("C_BPartner_ID", true, false, true, lookup);
				
	}   //  initBPartner

	/** Window No               */
	int               p_WindowNo;
	FormFrame 					m_frame;
	/** Model Tab               */
	//protected GridTab         		p_mTab;

	boolean             p_initOK = false;

	/** Loaded Order            */
	/**	Logger			*/
	CLogger 		log = CLogger.getCLogger(getClass());
	/**	Static Logger	*/
	//
	private CPanel parameterPanel = new CPanel();
	private BorderLayout parameterLayout = new BorderLayout();
	private CPanel parameterStdPanel = new CPanel();
	private JLabel bPartnerLabel = new JLabel();
	private GridBagLayout parameterStdLayout = new GridBagLayout();
	private VLookup bPartnerField;
	private JLabel shipmentLabel = new JLabel();
	private JScrollPane dataPane = new JScrollPane();
	private CPanel southPanel = new CPanel();
	private BorderLayout southLayout = new BorderLayout();
	private ConfirmPanel confirmPanel = new ConfirmPanel(true);
	private StatusBar statusBar = new StatusBar();
	private MiniTable dataTable = new MiniTable();
	private JLabel locatorLabel = new JLabel();
	private VLocator locatorField = new VLocator();
	//
	private JLabel loadingIDLabel = new JLabel();
	private CTextField loadingID = new CTextField();
	private JLabel barcodeLabel = new JLabel();
	private JLabel barcodeLabel2 = new JLabel();
	private JTextField barcodePN = new JTextField();
	private JLabel barcodeProductName = new JLabel();
	private VNumber barcodeQty = new VNumber();
	
	public static final String SELECT_ALL = "SelectAll";
	
	Vector<Vector<Object>> data = new Vector<Vector<Object>>();
	MLoading loading;
    
	/**
	 *  Static Init
	 *  @throws Exception
	 */
	private void jbInit() throws Exception
	{
		Font boldFont = new Font(getFont().getName(), Font.BOLD, 12);
		parameterPanel.setLayout(parameterLayout);
		parameterStdPanel.setLayout(parameterStdLayout);		
		bPartnerLabel.setText(Msg.getElement(Env.getCtx(), "C_BPartner_ID"));		
		shipmentLabel.setText(Msg.getElement(Env.getCtx(), "M_InOut_ID", true));
		locatorLabel.setText(Msg.translate(Env.getCtx(), "M_Locator_ID"));
		loadingIDLabel.setText("Nomor Loading:");
		loadingIDLabel.setFont(boldFont);		
        loadingID.setFont(boldFont);
        barcodeLabel.setText("Qty");
        barcodeLabel.setFont(boldFont);
        barcodeLabel2.setText("Scan barconde disini >>");
        barcodeLabel2.setFont(boldFont);
        barcodeProductName.setText("<Empty>");
        barcodePN.setFont(boldFont);
        barcodeQty.setValue(Env.ZERO);
		//
		m_frame.getContentPane().add(parameterPanel, BorderLayout.NORTH);
		
		parameterPanel.add(parameterStdPanel, BorderLayout.CENTER);
		parameterStdPanel.add(bPartnerLabel, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
			,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		parameterStdPanel.add(bPartnerField, new GridBagConstraints(3, 0, 1, 1, 0.0, 0.0
				,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 5), 0, 0));
		/**parameterStdPanel.add(shipmentLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0
			,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		parameterStdPanel.add(shipmentField,  new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 5), 0, 0));
			**/
		parameterStdPanel.add(locatorLabel, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.0
			,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
		parameterStdPanel.add(locatorField, new GridBagConstraints(3, 1, 1, 1, 0.0, 0.0
			,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 5), 0, 0));        
                m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);
        parameterStdPanel.add(loadingIDLabel, new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0
            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 0, 5, 5), 0, 0));        
                m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);
        parameterStdPanel.add(loadingID, new GridBagConstraints(3, 3, 1, 1, 0.0, 0.0
           ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 5), 0, 0));        
                m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);                   
        parameterStdPanel.add(barcodeLabel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0
            ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 0, 5, 5), 0, 0));        
            	m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);
        parameterStdPanel.add(barcodeQty, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0
           ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 5), 0, 0));        
                m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);
        parameterStdPanel.add(barcodeLabel2, new GridBagConstraints(2, 4, 1, 1, 0.0, 0.0
           ,GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 0, 5, 5), 0, 0));        
               	m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);                   
        parameterStdPanel.add(barcodePN, new GridBagConstraints(3, 4, 1, 1, 0.0, 0.0
            ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 5), 0, 0));        
            	m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);          	
        parameterStdPanel.add(barcodeProductName, new GridBagConstraints(4, 4, 1, 1, 0.0, 0.0
             ,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 0, 5, 5), 0, 0));        
              	m_frame.getContentPane().add(dataPane, BorderLayout.CENTER);
                             
                    
		dataPane.getViewport().add(dataTable, null);
		
		//
 		//
		// @Trifon
		AppsAction selectAllAction = new AppsAction (SELECT_ALL, KeyStroke.getKeyStroke(KeyEvent.VK_A, java.awt.event.InputEvent.ALT_MASK), null);
		
		CButton selectAllButton = (CButton)selectAllAction.getButton();
		selectAllButton.setMargin(new Insets (0, 10, 0, 10));
		selectAllButton.setDefaultCapable(true);
		selectAllButton.addActionListener(this);
//		confirmPanel.addButton(selectAllButton);
		//
		barcodePN.setActionCommand("Barcode");
		barcodeQty.addActionListener(this);
		barcodePN.addActionListener(this);
		//
		m_frame.getContentPane().add(southPanel, BorderLayout.SOUTH);
		southPanel.setLayout(southLayout);
		southPanel.add(confirmPanel, BorderLayout.CENTER);
		// Trifon End
		m_frame.getContentPane().add(southPanel, BorderLayout.SOUTH);
		southPanel.setLayout(southLayout);
		southPanel.add(confirmPanel, BorderLayout.CENTER);
		southPanel.add(statusBar, BorderLayout.SOUTH);	   
	}   //  jbInit

	/**
	 * 	Dispose
	 */
	public void dispose()
	{
		if (m_frame != null)
			m_frame.dispose();
		m_frame = null;
	}	//	dispose

	/**
	 *  Dynamic Init (prepare dynamic fields)
	 *  @throws Exception if Lookups cannot be initialized
	 */
	private void dynInit() throws Exception
	{
		
		log.config("");
		//  load Locator
		MLocatorLookup locator = new MLocatorLookup(Env.getCtx(), p_WindowNo);
		locatorField = new VLocator ("M_Locator_ID", true, false, true,	locator, p_WindowNo);
		int M_Locator_ID = Env.getContextAsInt(Env.getCtx(), "M_Locator_ID");
		locatorField.setValue(M_Locator_ID);

		initBPartner(false);
		bPartnerField.addVetoableChangeListener(this);
		locatorField.addVetoableChangeListener(this);
		locatorField.setMandatory(true);
		bPartnerField.setMandatory(true);
		loadingID.setMandatory(true);

		//  Translation
		statusBar.setStatusLine("Ready");
		statusBar.setStatusDB("-");

	}   //  dynInit

	
	
	/**************************************************************************
	 *  Action Listener.
	 *  @param e event
	 */
	public void actionPerformed(ActionEvent e)
	{
		boolean isError=false;
		if (e.getSource().equals(barcodePN)){
			if (bPartnerField.getValue()==null){
				ADialog.error(p_WindowNo, this, "Customer belum di isi!");
				bPartnerField.requestFocus();
				isError=true;
			}else if(locatorField.getValue()==null){
				ADialog.error(p_WindowNo, this, "Locator belum di isi!");
				locatorField.requestFocus();
				isError=true;
			}else if(loadingID.getText().equals("")){
				ADialog.error(p_WindowNo, this, "Nomor loading harus diisi");
				loadingID.requestFocus();
				isError=true;
			}else if(barcodeQty.getValue().equals(Env.ZERO)){
				ADialog.error(p_WindowNo, this, "Qty nol!");
				barcodeQty.requestFocus();
				isError=true;			
			}
			if (!isError){
				String trxName=Trx.createTrxName();
				String msg = addBarcodeLine(trxName);
				if (msg.equals("")){
					Trx.get(trxName, false).commit();
					statusBar.setStatusLine("Inserted!");					
			
				}else{
					Trx.get(trxName, false).rollback();
					ADialog.error(p_WindowNo, this, msg);
					statusBar.setStatusLine(msg);
				}
				barcodeQty.requestFocus();
			}
			resetValue();
		}else if(e.getSource().equals(barcodeQty)){
			barcodePN.requestFocusInWindow();
		}else if(e.getActionCommand().equals(ConfirmPanel.A_OK)){
			enableHeader(true);
			resetValue();
			loadingID.setText("");
			bPartnerField.setValue(null);
			bPartnerField.requestFocus();
			data.clear();
			loadTableOIS(data);
		}else if(e.getActionCommand().equals(ConfirmPanel.A_CANCEL)){
			dispose();
		}else{
			JOptionPane.showMessageDialog(this, e.getActionCommand());
		}
	}   //  actionPerformed
	
	private void resetValue(){
		barcodePN.setText("");
		barcodeProductName.setText("");
		barcodeQty.setValue(Env.ZERO);
	}
	
	private String addBarcodeLine(String trxName){
		//Get produk 
		barcodeProductName.setText("");
		String result="";
		//OLD query using m_productpo : String sql = "SELECT M_Product_ID FROM m_product_po WHERE  vendorproductno = ?";
		//New query using M_Product:
		String sql = "SELECT M_Product_ID FROM M_Product WHERE UPC = ?";
		int M_Product_ID=0;
		try
        {
            PreparedStatement pstmt = DB.prepareStatement(sql, trxName);
            pstmt.setString(1, barcodePN.getText().trim());            
            ResultSet rs = pstmt.executeQuery();
            if (rs.next())                        
                M_Product_ID = rs.getInt(1);            
            rs.close();
            pstmt.close();
            if (M_Product_ID == 0) result= "PN produk tidak benar!";
        }
        catch (SQLException e)
        {
            log.log(Level.SEVERE, sql.toString(), e);
            result= "Kesalahan dalam mencari kode produk";
        }
		if (result.length()!=0) return result;
		BigDecimal qty= (BigDecimal) barcodeQty.getValue();
		if (qty.signum()<=0) return "Qty harus lebih besar dari nol";
		//Cek apakah qty cukup
		sql = "SELECT SUM(line.movementqty-line.barcodecheckedqty) as sisa "
				+ "FROM m_inoutline line "
				+ "INNER JOIN m_inout io ON line.m_inout_id = io.m_inout_id "
				+ "WHERE line.m_product_id = ? AND line.m_locator_id = ? "   
				+ "AND line.movementqty <> line.barcodecheckedqty " 
				+ "AND (line.isbarcodechecked <> 'Y' OR line.isbarcodechecked IS NULL) "
				+ "AND io.c_bpartner_id = ? "
				+ "";
		try
        {
            PreparedStatement pstmt = DB.prepareStatement(sql, trxName);
            pstmt.setInt(1, M_Product_ID);            
            pstmt.setInt(2, (Integer) locatorField.getValue());
            pstmt.setInt(3, (Integer) bPartnerField.getValue());
            ResultSet rs = pstmt.executeQuery();
            BigDecimal sisa = Env.ZERO;
            if (rs.next())                        
               sisa= rs.getBigDecimal(1);
            if (sisa==null) sisa=Env.ZERO;
            if (sisa.compareTo(qty)<0)
            	result= "Jumlah produk pada shipment kurang dari qty yang di input!";
            rs.close();
            pstmt.close();         
        }
        catch (SQLException e)
        {
            log.log(Level.SEVERE, sql.toString(), e);
            result= "Kesalahan dalam menghitung qty produk";
        }
		if (result.length()!=0) return result;
		MProduct prd = MProduct.get(Env.getCtx(), M_Product_ID);
		if (prd==null) return "Produk tidak terdaftar";
		barcodeProductName.setText(prd.getName());
		if(!confirmPanel.isOKVisible()){
			loading = new MLoading(Env.getCtx(), 0, trxName);			
			loading.setDocumentno(loadingID.getText());
			loading.setLoadingDate(TimeUtil.getServerTime());
			loading.setM_Locator_ID((Integer) locatorField.getValue());
			loading.setC_BPartner_ID((Integer) bPartnerField.getValue());
			loading.save();
			enableHeader(false);
		}
		//Get list of shipmentline 
		//berdasarkan BPartner, MProduct
		
		sql = "SELECT line.m_inout_id, line.m_inoutline_id "
			+ "FROM m_inoutline line "
			+ "INNER JOIN m_inout io ON line.m_inout_id = io.m_inout_id "
			+ "WHERE line.m_product_id = ? AND line.m_locator_id = ? "   
			+ "AND line.movementqty <> line.barcodecheckedqty " 
			+ "AND (line.isbarcodechecked <> 'Y' OR line.isbarcodechecked IS NULL) "
			+ "AND io.c_bpartner_id = ? "
			+ "ORDER by line.m_inoutline_id DESC";		
		try
        {
            PreparedStatement pstmt = DB.prepareStatement(sql, trxName);
            pstmt.setInt(1, M_Product_ID);            
            pstmt.setInt(2, (Integer) locatorField.getValue());
            pstmt.setInt(3, (Integer) bPartnerField.getValue());
            ResultSet rs = pstmt.executeQuery();
            while (rs.next()){
            	MInOutLine line = new MInOutLine(Env.getCtx(), rs.getInt(2), trxName);
            	if (line.getQtyNotChecked().compareTo(qty)>=0) { //Cukup
            		line.setBarcodeCheckedQty(line.getBarcodeCheckedQty().add(qty));
            		line.save();
            		//
            		MLoadingLine loadingline = new MLoadingLine(Env.getCtx(), 0,loading.getM_Loading_ID() , trxName);
            		loadingline.setBarcodeCheckedQty(qty);            		
            		loadingline.setM_InOutLine_ID(line.getM_InOutLine_ID());
            		loadingline.save();
            		//
            		addData(barcodePN.getText().trim(), M_Product_ID,
            				barcodeProductName.getText().trim(), loadingline.getBarcodeCheckedQty().doubleValue(), 
            				line.getM_InOutLine_ID(), line.getParent().getDocumentNo());
            		break; //Keluar while
            	}else { //qty sisa tidak cukup
            		//
            		MLoadingLine loadingline = new MLoadingLine(Env.getCtx(), 0, loading.getM_Loading_ID() , trxName);
            		loadingline.setBarcodeCheckedQty(line.getQtyNotChecked());            		
            		loadingline.setM_InOutLine_ID(line.getM_InOutLine_ID());
            		loadingline.save();
            		//
            		qty=qty.subtract(line.getQtyNotChecked());
            		line.setBarcodeCheckedQty(line.getMovementQty());            		
            		line.save();
            		//
            		addData(barcodePN.getText().trim(), M_Product_ID,
            				barcodeProductName.getText().trim(), loadingline.getBarcodeCheckedQty().doubleValue(), 
            				line.getM_InOutLine_ID(), line.getParent().getDocumentNo());
            	}
            }
            rs.close();
            pstmt.close();
        }
        catch (SQLException e)
        {
            log.log(Level.SEVERE, sql.toString(), e);
            result= "Kesalahan!" + e.getMessage();
        }
		return result;
	}

	private void enableHeader(boolean enabled){	
		loadingID.setEditable(enabled);
		bPartnerField.setReadWrite(enabled);
		locatorField.setReadWrite(enabled);
		confirmPanel.setOKVisible(!enabled);
	}
	/**
	 *  Table Model Listener.
	 *  - Recalculate Totals
	 *  @param e event
	 */
	public void tableChanged(TableModelEvent e)
	{
		

	}   //  tableChanged

	/**
	 *  Calculate Allocation info
	 */
	
	/**
	 *  Vetoable Change Listener.
	 *  - Business Partner
	 *  - Currency
	 * 	- Date
	 *  @param e event
	 */
	public void vetoableChange (PropertyChangeEvent e)
	{
		/**String name = e.getPropertyName();
		Object value = e.getNewValue();
		log.config(name + "=" + value);
		if (value == null)
			return;

		int m_C_BPartner_ID=0;
		int m_M_Locator_ID=0;
		if (name.equals("C_BPartner_ID")){
			m_C_BPartner_ID = ((Integer)value).intValue();
			m_M_Locator_ID =locatorField.getM_Locator_ID();
		}else if(name.equals("M_Locator_ID")){
			m_M_Locator_ID = ((Integer)value).intValue();
			m_C_BPartner_ID= (Integer) bPartnerField.getValue();
		}**/
		//initBPShipmentDetails(m_C_BPartner_ID,m_M_Locator_ID );

	}   //  vetoableChange

	
		
		
	private void addData(String PartNumber, int MProductID,
						 String ProductName, double qty,
						 int ShipmentLineID,String DocNumber){
		Vector<Object> line = new Vector<Object>(4);
		line.add(PartNumber);				// 0-VendorProductNo
		KeyNamePair pp = new KeyNamePair(MProductID, ProductName);
		line.add(pp);                       //  1-Product
		line.add(qty);  					//  2-Qty
		pp = new KeyNamePair(ShipmentLineID, DocNumber);
		line.add(pp);                       //  3-Ship		
		data.add(line);
		loadTableOIS(data);
	}
	
	
	
	protected void loadTableOIS(Vector<Vector<Object>> data) {
		//  Header Info
		    Vector<String> columnNames = new Vector<String>(4);
		    columnNames.add(Msg.getElement(Env.getCtx(), "VendorProductNo", false));
		    columnNames.add(Msg.translate(Env.getCtx(), "M_Product_ID"));		    
		    columnNames.add(Msg.translate(Env.getCtx(), "Quantity"));		    
		    columnNames.add(Msg.getElement(Env.getCtx(), "M_InOutLine_ID", true));
		    
		    //  Remove previous listeners
		    dataTable.getModel().removeTableModelListener(this);
		    //  Set Model
		    DefaultTableModel model = new DefaultTableModel(data, columnNames);
		    model.addTableModelListener(this);
		    dataTable.setModel(model);
		    //		    
		    dataTable.setColumnClass(0, String.class, true);        //  1-VendorProductNo
		    dataTable.setColumnClass(1, String.class, true);        //  2-Product
		    dataTable.setColumnClass(2, Double.class, true);        //  3-Qty
		    dataTable.setColumnClass(3, String.class, true);        //  4-Ship
		    dataTable.autoSize();
		}
	
}


